package controller

import (
	"bufio"
	"github.com/gin-gonic/gin"
	"github.com/xuri/excelize/v2"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	"mime/multipart"
	"mygo/app/models"
	"mygo/app/tools"
	"path"
	"strconv"
	"strings"
	"sync"
	"time"
)

var Up = UploadController{}

type UploadController struct {
	db *gorm.DB
}

// 定义一种Rbr泛型包含models.t1和models.t2

// UploadFile
func (ctl *UploadController) UploadRbr(c *gin.Context) {
	var wg sync.WaitGroup
	var err error
	ctl.db = models.Db
	numOffset := c.Query("numOffset")
	file, err := c.FormFile("file")
	if err != nil {
		tools.ErrorResp(c, 500, "未知错误，请重新上传")
		return
	}
	//	获取文件名
	fileName := file.Filename
	//	获取文件后缀
	fileSuffix := path.Ext(fileName)
	//	判断文件后缀
	if fileSuffix != ".xlsx" {
		tools.ErrorResp(c, 500, "文件格式错误，请重新上传")
		return
	}
	//打开数据流
	f, _ := file.Open()
	xlsx, _ := excelize.OpenReader(f)
	for _, v := range xlsx.GetSheetMap() {
		wg.Add(1)
		go func(v string) {
			defer wg.Done()
			//牺牲内存换取速度
			fTemp, _ := file.Open()
			xlsxTemp, _ := excelize.OpenReader(fTemp)
			rows, _ := xlsxTemp.GetRows(v)
			if len(rows) > 10000 {
				if strings.Contains(fileName, "t1") || strings.Contains(fileName, "T1") {
					dealSheetCut(rows, v, &wg, ctl.db, numOffset, "t1")
				} else {
					dealSheetCut(rows, v, &wg, ctl.db, numOffset, "t2")
				}
			}
		}(v)

		//rows, _ := xlsx.GetRows(v)
		//if len(rows) > 1000000 {
		//	wg.Add(1)
		//	go func() {
		//		defer wg.Done()
		//		fmt.Println(len(rows))
		//		wg.Add(1)
		//		if strings.Contains(fileName, "t1") || strings.Contains(fileName, "T1") {
		//			go dealSheetCut(rows, v, &wg, ctl.db, numOffset, "t1")
		//		} else {
		//			go dealSheetCut(rows, v, &wg, ctl.db, numOffset, "t2")
		//		}
		//	}()
		//}
		//var arr [][]string
		//rowsIterator, _ := xlsx.Rows(v)
		//if strings.Contains(v, "Data") {
		//	index := 0
		//	for rowsIterator.Next() {
		//		index++
		//		cell, _ := xlsx.GetCellValue(v, "A"+strconv.Itoa(index))
		//		//row, _ := rowsIterator.Columns()
		//		arr = append(arr, []string{cell})
		//	}
		//	fmt.Println(len(arr))
		//}
	}
	wg.Wait()
	date := time.Now().Format("2006-01-02")
	var fileList models.FileList
	fileList.FileName = file.Filename
	fileList.CreateTime = date
	fileList.State = "上传成功"
	ctl.db.Create(&fileList)
	tools.SuccessResp(c, "上传成功", "555")
}

func dealSheet(rows [][]string, sheetName string, wg *sync.WaitGroup, db *gorm.DB, numOffset string) {
	defer wg.Done()
	var channel = make(chan models.Rbr, 1000000)
	wg.Add(1)
	go putData(channel, rows, sheetName, wg, numOffset)

	for i := 0; i < 8; i++ {
		wg.Add(1)
		go saveData(channel, wg, db, numOffset)
	}
}

func dealSheetCut(rows [][]string, sheetName string, wg *sync.WaitGroup, db *gorm.DB, numOffset, fileName string) {
	//defer wg.Done()
	var channel = make(chan models.RbrCut, 100000)
	wg.Add(1)
	go putDataCut(channel, rows, sheetName, wg, numOffset, fileName)

	for i := 0; i < 2; i++ {
		wg.Add(1)
		go saveDataCut(channel, wg, db, numOffset)
	}
}

func putData(channel chan models.Rbr, rows [][]string, sheetName string, wg *sync.WaitGroup, numOffset string) {
	for index, row := range rows {
		if index > 2 {
			var test models.Rbr
			timeFloat, _ := strconv.ParseFloat(row[0], 64)
			timeResult := tools.ExcelDateToDate(timeFloat)
			depthFloat, _ := strconv.ParseFloat(row[3], 64)
			numOffsetFloat, _ := strconv.ParseFloat(numOffset, 64)
			depthFloat += numOffsetFloat
			depth := strconv.FormatFloat(depthFloat, 'f', -1, 64)
			test.Time = timeResult
			test.Depth = depth
			channel <- test
		}
	}
	close(channel)
	wg.Done()
}

// 1200 跨度10分钟
func putDataCut(channel chan models.RbrCut, rows [][]string, sheetName string, wg *sync.WaitGroup, numOffset, fileName string) {
	for index, row := range rows {
		//if len(rows)-index < 7300 {
		//	return
		//}
		if index > 7300 && index < len(rows)-7300 {
			depthFloat, _ := strconv.ParseFloat(row[3], 64)
			//depthFloatLast, _ := strconv.ParseFloat(rows[index-1][3], 64)
			//depthFloatNext, _ := strconv.ParseFloat(rows[index+1][3], 64)
			isHigh := true

			for i := index; i < index+7000; i++ {
				depthTemp := rows[i][3]
				depthTempFloat, _ := strconv.ParseFloat(depthTemp, 64)
				if depthTempFloat > depthFloat {
					isHigh = false
					break
				}
			}

			for i := index; i > index-7000; i-- {
				if !isHigh {
					break
				}
				depthTemp := rows[i][3]
				depthTempFloat, _ := strconv.ParseFloat(depthTemp, 64)
				if depthTempFloat > depthFloat {
					isHigh = false
					break
				}
			}

			if isHigh && depthFloat > 0.5 {
				var test models.RbrCut
				timeResult := ""
				if strings.Contains(row[0], ":") {
					timeResult = row[0]
				} else {
					timeFloat, _ := strconv.ParseFloat(row[0], 64)
					timeResult = tools.ExcelDateToDate(timeFloat)
				}
				//timeFloat, _ := strconv.ParseFloat(row[0], 64)
				//timeResult := tools.ExcelDateToDate(timeFloat)
				numOffsetFloat, _ := strconv.ParseFloat(numOffset, 64)
				depthFloat += numOffsetFloat
				depth := strconv.FormatFloat(depthFloat, 'f', -1, 64)
				test.Time = timeResult
				test.Depth = depth
				test.IsTop = "1"
				test.Station = fileName
				channel <- test
				continue
			}

			//timeFloat, _ := strconv.ParseFloat(row[0], 64)
			//timeResult := tools.ExcelDateToDate(timeFloat)

			timeResult := ""
			if strings.Contains(row[0], ":") {
				timeResult = row[0]
			} else {
				timeFloat, _ := strconv.ParseFloat(row[0], 64)
				timeResult = tools.ExcelDateToDate(timeFloat)
			}

			if tools.IsHalfHour(timeResult) {
				var test models.RbrCut
				numOffsetFloat, _ := strconv.ParseFloat(numOffset, 64)
				depthFloat += numOffsetFloat
				depth := strconv.FormatFloat(depthFloat, 'f', -1, 64)
				test.Time = timeResult
				test.Depth = depth
				test.IsTop = "0"
				test.Station = fileName
				channel <- test
			}
		} else if index > 5 {
			depthFloat, _ := strconv.ParseFloat(row[3], 64)
			timeResult := ""
			if strings.Contains(row[0], ":") {
				timeResult = row[0]
			} else {
				timeFloat, _ := strconv.ParseFloat(row[0], 64)
				timeResult = tools.ExcelDateToDate(timeFloat)
			}
			if tools.IsHalfHour(timeResult) {
				var test models.RbrCut
				numOffsetFloat, _ := strconv.ParseFloat(numOffset, 64)
				depthFloat += numOffsetFloat
				depth := strconv.FormatFloat(depthFloat, 'f', -1, 64)
				test.Time = timeResult
				test.Depth = depth
				test.IsTop = "0"
				test.Station = fileName
				channel <- test
			}
		}
	}
	close(channel)
	wg.Done()
}

func putDataCutTest(channel chan models.RbrCut, rows [][]string, sheetName string, wg *sync.WaitGroup, numOffset, fileName string) {
	for index, row := range rows {
		if index > 7300 && index < len(rows)-7300 {
			depthFloat, _ := strconv.ParseFloat(row[3], 64)
			//depthFloatLast, _ := strconv.ParseFloat(rows[index-1][3], 64)
			//depthFloatNext, _ := strconv.ParseFloat(rows[index+1][3], 64)
			isHigh := true

			for i := index; i < index+7000; i++ {
				depthTemp := rows[i][3]
				depthTempFloat, _ := strconv.ParseFloat(depthTemp, 64)
				if depthTempFloat > depthFloat {
					isHigh = false
					break
				}
			}

			for i := index; i > index-7000; i-- {
				if !isHigh {
					break
				}
				depthTemp := rows[i][3]
				depthTempFloat, _ := strconv.ParseFloat(depthTemp, 64)
				if depthTempFloat > depthFloat {
					isHigh = false
					break
				}
			}

			if isHigh && depthFloat > 0.5 {
				var test models.RbrCut
				timeResult := ""
				if strings.Contains(row[0], ":") {
					timeResult = row[0]
				} else {
					timeFloat, _ := strconv.ParseFloat(row[0], 64)
					timeResult = tools.ExcelDateToDate(timeFloat)
				}
				//timeFloat, _ := strconv.ParseFloat(row[0], 64)
				//timeResult := tools.ExcelDateToDate(timeFloat)
				numOffsetFloat, _ := strconv.ParseFloat(numOffset, 64)
				depthFloat += numOffsetFloat
				depth := strconv.FormatFloat(depthFloat, 'f', -1, 64)
				test.Time = timeResult
				test.Depth = depth
				test.IsTop = "1"
				test.Station = fileName
				channel <- test
				continue
			}

			//timeFloat, _ := strconv.ParseFloat(row[0], 64)
			//timeResult := tools.ExcelDateToDate(timeFloat)

			timeResult := ""
			if strings.Contains(row[0], ":") {
				timeResult = row[0]
			} else {
				timeFloat, _ := strconv.ParseFloat(row[0], 64)
				timeResult = tools.ExcelDateToDate(timeFloat)
			}

			if tools.IsHalfHour(timeResult) {
				var test models.RbrCut
				numOffsetFloat, _ := strconv.ParseFloat(numOffset, 64)
				depthFloat += numOffsetFloat
				depth := strconv.FormatFloat(depthFloat, 'f', -1, 64)
				test.Time = timeResult
				test.Depth = depth
				test.IsTop = "0"
				test.Station = fileName
				channel <- test
			}
		} else if index > 5 {
			depthFloat, _ := strconv.ParseFloat(row[3], 64)
			timeResult := ""
			if strings.Contains(row[0], ":") {
				timeResult = row[0]
			} else {
				timeFloat, _ := strconv.ParseFloat(row[0], 64)
				timeResult = tools.ExcelDateToDate(timeFloat)
			}
			if tools.IsHalfHour(timeResult) {
				var test models.RbrCut
				numOffsetFloat, _ := strconv.ParseFloat(numOffset, 64)
				depthFloat += numOffsetFloat
				depth := strconv.FormatFloat(depthFloat, 'f', -1, 64)
				test.Time = timeResult
				test.Depth = depth
				test.IsTop = "0"
				test.Station = fileName
				channel <- test
			}
		}
	}
	close(channel)
	wg.Done()
}
func saveData(channel chan models.Rbr, wg *sync.WaitGroup, db *gorm.DB, numOffset string) {
	defer wg.Done()
	var testList []models.Rbr
	for test := range channel {
		testList = append(testList, test)
		if len(testList) == 2000 {
			models.Db.Clauses(clause.OnConflict{
				Columns:   []clause.Column{{Name: "time"}},
				DoUpdates: clause.AssignmentColumns([]string{"depth"}),
			}).Create(&testList)
			testList = nil
		}
	}
}

func saveDataCut(channel chan models.RbrCut, wg *sync.WaitGroup, db *gorm.DB, numOffset string) {
	defer wg.Done()
	var err error
	for test := range channel {
		err = db.Model(&models.RbrCut{}).Where("time = ? AND station = ?", test.Time, test.Station).First(&models.RbrCut{}).Error
		if err != nil {
			db.Create(&test)
		} else {
			db.Model(&models.RbrCut{}).Where("time = ? AND station = ?", test.Time, test.Station).Update("depth", test.Depth)
		}
	}
}

// UploadFb
func (ctl *UploadController) UploadFb(c *gin.Context) {
	var err error
	ctl.db = models.Db
	file, err := c.FormFile("file")
	if err != nil {
		tools.ErrorResp(c, 500, "未知错误，请重新上传")
		return
	}
	fileName := file.Filename
	//	获取文件后缀
	fileSuffix := path.Ext(fileName)
	//	判断文件后缀
	if fileSuffix == ".xlsx" {
		//tools.ErrorResp(c, 500, "文件格式错误，请重新上传")
		dealFbXlsx(file, fileName)
		tools.SuccessResp(c, "上传成功", "555")
		return
	}
	f, _ := file.Open()
	//	用完记得关闭
	defer f.Close()
	reader := bufio.NewReader(f)
	contents, _ := reader.ReadString('\n')
	contentsArr := strings.Split(contents, " ")
	//去除空格
	var contentsArr2 []string
	for _, v := range contentsArr {
		if v != "" {
			contentsArr2 = append(contentsArr2, v)
		}
	}
	var fb models.Fb
	t := contentsArr2[0]
	fb.Time = t[0:4] + "-" + t[4:6] + "-" + t[6:8] + " " + t[8:10] + ":" + t[10:12]
	fb.Hs = contentsArr2[8]
	fb.Tp = contentsArr2[9]
	fb.Dir = contentsArr2[10]
	fb.Station = "浅滩"
	models.Db.Clauses(clause.OnConflict{
		Columns:   []clause.Column{{Name: "idx_time_station"}},
		DoUpdates: clause.AssignmentColumns([]string{"hs", "tp", "dir"}),
	}).Create(&fb)
	date := time.Now().Format("2006-01-02")
	var fileList models.FileList
	fileList.FileName = file.Filename
	fileList.CreateTime = date
	fileList.State = "上传成功"
	ctl.db.Create(&fileList)
	tools.SuccessResp(c, "上传成功", "555")
}

func dealFbXlsx(file *multipart.FileHeader, name string) {
	f, _ := file.Open()
	xlsx, _ := excelize.OpenReader(f)
	if strings.Contains(name, "三澳") {
		dealFbXlsxSa(xlsx)
		return
	}
	for _, v := range xlsx.GetSheetMap() {
		rows, _ := xlsx.GetRows(v)
		if len(rows) == 0 {
			continue
		}
		for index, row := range rows {
			if index == 0 {
				continue
			}
			//fmt.Println(row[1])
			//fmt.Println(tools.FormatTime(row[1]))
			var fb models.Fb
			fb.Time = tools.FormatTime(row[1])
			fb.Hs = row[14]
			fb.Tp = row[15]
			fb.Dir = row[19]
			fb.Station = "浅滩"
			models.Db.Clauses(clause.OnConflict{
				Columns:   []clause.Column{{Name: "idx_time_station"}},
				DoUpdates: clause.AssignmentColumns([]string{"hs", "tp", "dir"}),
			}).Create(&fb)
		}
	}
}

// SavePng
//func (ctl *UploadController) SavePng(c *gin.Context) {
//	fileName := c.Query("fileName")
//	t := c.Query("time")
//	fileType := c.Query("type")
//	var err error
//	//	接收文件
//	file, err := c.FormFile("file")
//	if err != nil {
//		tools.ErrorResp(c, 500, "未知错误，请重新上传")
//		return
//	}
//	filePath := "./public/img/" + fileType + "/" + t
//	//	创建文件夹
//	err = os.MkdirAll(filePath, os.ModePerm)
//	if err != nil {
//		tools.ErrorResp(c, 500, "未知错误，请重新上传")
//		return
//	}
//
//	finalPath := filePath + "/" + fileName
//	//	保存
//	err = c.SaveUploadedFile(file, finalPath)
//	if err != nil {
//		tools.ErrorResp(c, 500, "未知错误，请重新上传")
//		return
//	}
//	tools.SuccessResp(c, "上传成功", "555")
//
//}

// dealFbXlsxSa
func dealFbXlsxSa(xlsx *excelize.File) {
	for _, v := range xlsx.GetSheetMap() {
		rows, _ := xlsx.GetRows(v)
		for _, row := range rows {
			if len(row) != 34 {
				continue
			}
			if strings.Contains(row[0], "站位") {
				continue
			}
			var fb models.Fb
			fb.Time = row[2]
			fb.Hs = row[31]
			fb.Tp = row[32]
			fb.Dir = row[33]
			fb.Station = "三澳"
			models.Db.Clauses(clause.OnConflict{
				Columns:   []clause.Column{{Name: "idx_time_station"}},
				DoUpdates: clause.AssignmentColumns([]string{"hs", "tp", "dir"}),
			}).Create(&fb)
		}
	}
}

func (ctl *UploadController) SavePng(c *gin.Context) {
	ctl.db = models.Db
	//	接收文件,存到./public/txt
	file, _ := c.FormFile("file")
	//如果不是docx
	if !strings.Contains(file.Filename, "png") {
		c.JSON(200, gin.H{
			"code":    500,
			"message": "请上传png格式",
		})
		return
	}
	filePath := "./public/png/" + file.Filename
	//	获得一个随机数
	//c.SaveUploadedFile(file, filePath)

	//随机保存或者什么都不做

	c.SaveUploadedFile(file, filePath)

	c.JSON(200, gin.H{
		"code":    200,
		"message": "上传成功",
	})
}
